// compile.hpp只负责编译
#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace NS_Compiler
{
    using namespace NS_Util;
    using namespace NS_Log;

    //编译远端提交的临时文件
    //结果：
    //  1.通过
    //  2.出错：需要形成临时文件，保存编译出错的结果
    //  子进程完成编译工作向父进程输出错误信息
    class Compiler
    {
    public:
        Compiler()
        {}
        ~Compiler()
        {}

        // ret: 编译是否成功
        // file_name: 编译文件名
        // ./temp/123.cpp
        // ./temp/123.exe
        // ./temp/123.err
        static bool Compile(const std::string& file_name)
        {
            pid_t pid = fork();

            if (pid == 0) /* child */
            {
                umask(0);
                int cerr_fd = FileUtil::OpenFile(PathUtil::CompilerError(file_name));

                dup2(cerr_fd, 2); // 将报错信息重定向至.stderr文件中

                //g++ -o 123.exe 123.cpp -std=c++11
                execlp(
                    "g++",
                    "g++",
                    "-o",
                    PathUtil::Exe(file_name).c_str(),
                    PathUtil::Src(file_name).c_str(),
                    "-std=c++11",
                    "-D", "COMPILER_SERVER", // 加条件编译头以去掉tail.cpp中的头文件引用
                    nullptr
                );

                LOG(ERROR) << "compile(g++) file failed, maybe exec's arguments were wrong\n";
                exit(2);
            }
            else if (pid > 0) /* parent */
            {
                waitpid(pid, nullptr, 0);

                if (FileUtil::IsFileExists(PathUtil::Exe(file_name))) // 编译成功
                {
                    LOG(INFO) << "compiler compile(g++) success, generate " << PathUtil::Exe(file_name) << '\n';
                    return true;
                }
                else
                {
                    LOG(INFO) << "compiler compile(g++) failed, cannot generate exe file" << '\n';
                    return false;
                }

            }
            else /* pid < 0 error */
            {
                LOG(ERROR) << "compiler child proccess create failed\n";
                return false;
            }

        }

    };

}
